import { Injectable } from '@nestjs/common';
import {StudentEntity} from "../../eduation/student/entities/student.entity";
import {Repository} from "typeorm";
import {InjectRepository} from "@nestjs/typeorm";
import {ResultData} from "../../../common/utils/result";
import * as nodemailer from 'nodemailer'
import {ConfigService} from "@nestjs/config";
import {RedisService} from "../../common/redis/redis.service";
import {CacheEnum} from "../../../common/enum";
import * as jwt from 'jsonwebtoken'
import {resetPwdDto} from "./dto/req-web-user.dto";
import * as bcrypt from "bcryptjs";
@Injectable()
export class WebUserService {

    private transporter: nodemailer.Transporter


    constructor(
        @InjectRepository(StudentEntity)
        private readonly studentEntityRep:Repository<StudentEntity>,
        protected readonly config: ConfigService,
        private readonly redisService: RedisService,
    ) {
        this.transporter = nodemailer.createTransport({
            service:config.get('email.service'),
            auth:{
                user:config.get('email.user'),
                pass:config.get('email.pass')
            }
        })
    }


    async findByCount(account:string){
        return await this.studentEntityRep.findOne({
            where: [
                { delFlag: '0', username: account },
                { delFlag: '0', phone: account },
                { delFlag: '0', email: account }
            ]
        });
    }

    async findByFilter(filter:Record<string, any>) {
        return await  this.studentEntityRep.findOne({
            where:{
                ...filter,
                delFlag:'0'
            }
        })
    }


    /**
     * 添加
     */
    async create(body: StudentEntity) {
        await this.studentEntityRep.save(body)
        return ResultData.ok(true,'注册成功')
    }

    /**
     * 发送验证码到邮箱
     * @param email
     */
    async sendEmailVerificationCode(email: string) {
        // 1. 校验邮箱格式
        const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
        if (!emailRegex.test(email)) {
            return  ResultData.fail(400, '请输入有效的邮箱地址')
        }
        // 2. 检查是否在发送间隔内
        const lastSent = await this.redisService.get(`${CacheEnum.EMAIL_SEND_KEY}${email}`);
        const interval = this.config.get('email.interval') || 60 // 默认60秒
        if (lastSent && Date.now() - parseInt(lastSent, 10) < interval * 1000) {
            return  ResultData.fail(400, `请${interval}秒后再发送`)
        }
        // 3. 生成验证码
        const code = this.generateVerificationCode()
        // 4. 存储验证码到 Redis，设置过期时间
        const expiresInSeconds = (this.config.get('email.expiresIn') || 5) * 60
        await this.redisService.set(`${CacheEnum.EMAIL_CODE_KEY}${email}`,code,expiresInSeconds * 1000)
        // 5. 记录发送时间
        await this.redisService.set(`${CacheEnum.EMAIL_SEND_KEY}${email}`, (new Date()).getTime(), interval * 1000)
        // 6. 构造邮件内容
        const subject = '找回密码验证码'
        const text = `您的验证码是：${code}，${expiresInSeconds / 60}分钟内有效`
        const html = `<p>您的验证码是：<strong>${code}</strong></p><p>${expiresInSeconds / 60}分钟内有效</p>`
        const title = this.config.get('web.title');
        const fromEmail = this.config.get('email.user');
        const mailOptions = {
            from: `"${title}" <${fromEmail}>`,
            to: email,
            subject,
            text,
            html,
        }
        // 7. 发送邮件
        try {
            await this.transporter.sendMail(mailOptions)
            return ResultData.ok(true,'验证码发送成功')
        } catch (error) {
            console.error('邮件发送失败:', error.message)
            throw new Error('邮件发送失败，请稍后重试')
        }
    }

    /**
     * 生成6位随机验证码
     */
    private generateVerificationCode(): string {
        return Math.floor(100000 + Math.random() * 900000).toString()
    }

    /**
     * 验证验证码并生成密钥
     * @param account
     * @param code
     * @param mark
     */
    async verifyCodeAndGenerateKey(account:string, code: string, mark:string){
        let key = ''
        if(mark === 'email'){
            key = CacheEnum.EMAIL_CODE_KEY+account
        }
        // 判断验证码是否存在
        const storedCode = await this.redisService.get(key)
        if (!storedCode) {
            return ResultData.fail(400, '验证码已过期')
        }
        // 判断验证码是否正确
        if (storedCode !== code) {
            return ResultData.fail(400, '验证码错误')
        }
        // 生成密钥 token秘钥，返回给前端用于密码重置
        const jwtSecret = this.config.get('email.jwt.secretKey')
        const jwtExpiry = this.config.get('email.jwt.jwtExpiry')
        const secretKey = jwt.sign({ account,mark }, jwtSecret, {
            expiresIn: jwtExpiry
        })
        return ResultData.ok(secretKey)
    }

    /**
     * 重置密码
     * @param body
     */
    async resetPassword(body: resetPwdDto) {
        const { token, password } = body;
        // 1. 验证 token 是否有效
        let decoded;
        try {
            const jwtSecret = this.config.get('email.jwt.secretKey');
            decoded = jwt.verify(token, jwtSecret) as { account: string; mark: string };
        } catch (error) {
            return ResultData.fail(400, '无效或过期的 token');
        }

        const { account, mark } = decoded;
        // 2. 构建查询条件
        const filter: Record<string, any> = {};
        if (mark === 'email') {
            filter.email = account;
        } else if (mark === 'phone') {
            filter.phone = account;
        } else {
            return ResultData.fail(400, '不支持的重置方式');
        }
        // 3. 查询用户是否存在
        const user:StudentEntity = await this.findByFilter(filter);
        if (!user) {
            return ResultData.fail(400, '用户不存在');
        }
        // 4. 加密新密码（假设你有一个加密方法）
        // 这里假设你用 bcrypt 加密
        const hashedPassword =  bcrypt.hashSync(password + user.salt, 10);

        // 5. 更新密码
        await this.studentEntityRep.update(user.studentId, {
            password: hashedPassword,
        });

        return ResultData.ok(null, '密码重置成功');

    }
}
